home *** CD-ROM | disk | FTP | other *** search
/ Komputer for Alle 2004 #2 / K-CD-2-2004.ISO / OpenOffice Sv / f_0397 / python-core-2.2.2 / lib / pty.py < prev    next >
Encoding:
Python Source  |  2003-07-18  |  4.8 KB  |  168 lines

  1. """Pseudo terminal utilities."""
  2.  
  3. # Bugs: No signal handling.  Doesn't set slave termios and window size.
  4. #       Only tested on Linux.
  5. # See:  W. Richard Stevens. 1992.  Advanced Programming in the
  6. #       UNIX Environment.  Chapter 19.
  7. # Author: Steen Lumholt -- with additions by Guido.
  8.  
  9. from select import select
  10. import os
  11.  
  12. # Absurd:  import termios and then delete it.  This is to force an attempt
  13. # to import pty to raise an ImportError on platforms that lack termios.
  14. # Without this explicit import of termios here, some other module may
  15. # import tty first, which in turn imports termios and dies with an
  16. # ImportError then.  But since tty *does* exist across platforms, that
  17. # leaves a damaged module object for tty in sys.modules, and the import
  18. # of tty here then appears to work despite that the tty imported is junk.
  19. import termios
  20. del termios
  21.  
  22. import tty
  23.  
  24. __all__ = ["openpty","fork","spawn"]
  25.  
  26. STDIN_FILENO = 0
  27. STDOUT_FILENO = 1
  28. STDERR_FILENO = 2
  29.  
  30. CHILD = 0
  31.  
  32. def openpty():
  33.     """openpty() -> (master_fd, slave_fd)
  34.     Open a pty master/slave pair, using os.openpty() if possible."""
  35.  
  36.     try:
  37.         return os.openpty()
  38.     except (AttributeError, OSError):
  39.         pass
  40.     master_fd, slave_name = _open_terminal()
  41.     slave_fd = slave_open(slave_name)
  42.     return master_fd, slave_fd
  43.  
  44. def master_open():
  45.     """master_open() -> (master_fd, slave_name)
  46.     Open a pty master and return the fd, and the filename of the slave end.
  47.     Deprecated, use openpty() instead."""
  48.  
  49.     try:
  50.         master_fd, slave_fd = os.openpty()
  51.     except (AttributeError, OSError):
  52.         pass
  53.     else:
  54.         slave_name = os.ttyname(slave_fd)
  55.         os.close(slave_fd)
  56.         return master_fd, slave_name
  57.  
  58.     return _open_terminal()
  59.  
  60. def _open_terminal():
  61.     """Open pty master and return (master_fd, tty_name).
  62.     SGI and generic BSD version, for when openpty() fails."""
  63.     try:
  64.         import sgi
  65.     except ImportError:
  66.         pass
  67.     else:
  68.         try:
  69.             tty_name, master_fd = sgi._getpty(os.O_RDWR, 0666, 0)
  70.         except IOError, msg:
  71.             raise os.error, msg
  72.         return master_fd, tty_name
  73.     for x in 'pqrstuvwxyzPQRST':
  74.         for y in '0123456789abcdef':
  75.             pty_name = '/dev/pty' + x + y
  76.             try:
  77.                 fd = os.open(pty_name, os.O_RDWR)
  78.             except os.error:
  79.                 continue
  80.             return (fd, '/dev/tty' + x + y)
  81.     raise os.error, 'out of pty devices'
  82.  
  83. def slave_open(tty_name):
  84.     """slave_open(tty_name) -> slave_fd
  85.     Open the pty slave and acquire the controlling terminal, returning
  86.     opened filedescriptor.
  87.     Deprecated, use openpty() instead."""
  88.  
  89.     return os.open(tty_name, os.O_RDWR)
  90.  
  91. def fork():
  92.     """fork() -> (pid, master_fd)
  93.     Fork and make the child a session leader with a controlling terminal."""
  94.  
  95.     try:
  96.         pid, fd = os.forkpty()
  97.     except (AttributeError, OSError):
  98.         pass
  99.     else:
  100.         if pid == CHILD:
  101.             try:
  102.                 os.setsid()
  103.             except OSError:
  104.                 # os.forkpty() already set us session leader
  105.                 pass
  106.         return pid, fd
  107.  
  108.     master_fd, slave_fd = openpty()
  109.     pid = os.fork()
  110.     if pid == CHILD:
  111.         # Establish a new session.
  112.         os.setsid()
  113.         os.close(master_fd)
  114.  
  115.         # Slave becomes stdin/stdout/stderr of child.
  116.         os.dup2(slave_fd, STDIN_FILENO)
  117.         os.dup2(slave_fd, STDOUT_FILENO)
  118.         os.dup2(slave_fd, STDERR_FILENO)
  119.         if (slave_fd > STDERR_FILENO):
  120.             os.close (slave_fd)
  121.  
  122.     # Parent and child process.
  123.     return pid, master_fd
  124.  
  125. def _writen(fd, data):
  126.     """Write all the data to a descriptor."""
  127.     while data != '':
  128.         n = os.write(fd, data)
  129.         data = data[n:]
  130.  
  131. def _read(fd):
  132.     """Default read function."""
  133.     return os.read(fd, 1024)
  134.  
  135. def _copy(master_fd, master_read=_read, stdin_read=_read):
  136.     """Parent copy loop.
  137.     Copies
  138.             pty master -> standard output   (master_read)
  139.             standard input -> pty master    (stdin_read)"""
  140.     while 1:
  141.         rfds, wfds, xfds = select(
  142.                 [master_fd, STDIN_FILENO], [], [])
  143.         if master_fd in rfds:
  144.             data = master_read(master_fd)
  145.             os.write(STDOUT_FILENO, data)
  146.         if STDIN_FILENO in rfds:
  147.             data = stdin_read(STDIN_FILENO)
  148.             _writen(master_fd, data)
  149.  
  150. def spawn(argv, master_read=_read, stdin_read=_read):
  151.     """Create a spawned process."""
  152.     if type(argv) == type(''):
  153.         argv = (argv,)
  154.     pid, master_fd = fork()
  155.     if pid == CHILD:
  156.         apply(os.execlp, (argv[0],) + argv)
  157.     try:
  158.         mode = tty.tcgetattr(STDIN_FILENO)
  159.         tty.setraw(STDIN_FILENO)
  160.         restore = 1
  161.     except tty.error:    # This is the same as termios.error
  162.         restore = 0
  163.     try:
  164.         _copy(master_fd, master_read, stdin_read)
  165.     except (IOError, OSError):
  166.         if restore:
  167.             tty.tcsetattr(STDIN_FILENO, tty.TCSAFLUSH, mode)
  168.